home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
vol6n9.arc
/
DRAW.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-02-16
|
35KB
|
757 lines
; Draw.asm
CODE SEGMENT ;*************************
ASSUME CS:CODE,DS:CODE ;* *
ORG 100H ;* REMEMBER TO EXE2BIN *
;* *
START: JMP BEGINNING ;*************************
COPYRIGHT DB 'Copyright 1987 Ziff-Davis Publishing Co.',1AH
PROGRAMMER DB 'Michael J. Mefford'
FILE DB 'DRAW.DAT',0
PARA_FLAG DB 0
FILE_FLAG DB 0
POLL_KEY DB 0
X_POSITION DW 319
Y_POSITION DW 99
X_BOUNDRY DW 599
Y_BOUNDRY EQU 199
X_DIRECTION DW ?
Y_DIRECTION DW ?
X_TEMP DW ?
Y_TEMP DW ?
DELTA_X DW ?
DELTA_Y DW ?
HALF_X DW ?
HALF_Y DW ?
COUNT DW ?
DIRECTION DW ?
COLOR DB 1
UPDATE_FLAG DB 1
PLOT_FLAG DB 1
NEW_COLOR DB ?
MAX_COLOR DB 1
BORDER DB ?
LEFT_X DW ?
RIGHT_X DW ?
NEXT_LEFT DW ?
NEXT_RIGHT DW ?
MONOCHROME DB 'Draw requires CGA adapter.$'
;----------------------------------------------------------;
; Exit if attempting to run on a monochrome system. ;
; Capitalize command line and check for switch characters. ;
;----------------------------------------------------------;
BEGINNING: MOV AX,40H ;Point to BIOS data segment.
MOV DS,AX
CMP DS:[63H],3B4H ;Is it a monochrome adapter?
PUSH CS
POP DS
JNZ CK_PARAMETERS ;If no, check parameters.
MOV DX,OFFSET MONOCHROME ;Else, display error message.
MOV AH,9
INT 21H
INT 20H ;And terminate.
CK_PARAMETERS: CMP BYTE PTR DS:[80H],0 ;Are there any parameters?
JZ PARAMETERS ;If no, open DRAW.DAT
CAPITALIZE: MOV SI,81H ;Point to parameters.
NEXT_CAP: LODSB ;Get a byte.
CMP AL,13 ;Is it carriage return?
JZ PARAMETERS ;If yes, done here.
CMP AL,'/' ;Is it switch character?
JZ SWITCHES ;If yes, check which one.
CMP AL,'0' ;Is it a possible command?
JB NEXT_CAP ;If no, get next byte.
MOV PARA_FLAG,1 ;Else flag that parameter exists.
CMP AL,'a' ;Is it lower case?
JB NEXT_CAP ;If no, get next byte.
AND BYTE PTR [SI-1],5FH ;Else, capitalize.
JMP SHORT NEXT_CAP ;Next byte.
SWITCHES: CMP AL,'/' ;Is it switch character?
JNZ GET_SWITCH ;If no, get next byte.
MOV BYTE PTR [SI-1],0 ;Else create ASCIIZ for DOS.
GET_SWITCH: LODSB ;Get a byte.
CMP AL,13 ;Is it carriage return?
JZ PARAMETERS ;If yes, done here.
AND AL,5FH ;Else, capitalize.
CMP AL,'K' ;Is it /K switch?
JNZ CK_FILE ;If no, check /F.
MOV POLL_KEY,1 ;Else, flag as no keyboard poll.
CK_FILE: CMP AL,'F' ;Is it /F?
JNZ SWITCHES ;If no, get next byte.
MOV FILE_FLAG,1 ;Else, flag as filespec.
JMP SHORT SWITCHES ;Get next byte.
;-----------------------------------------------------------------;
; Check to see if parameters exist and if yes check if filespec. ;
; If yes, read file into buffer and process by stripping Wordstar ;
; high bit, capitalizing, stripping comments and stripping space ;
; characters and below. Finish by tacking on a carriage return. ;
;-----------------------------------------------------------------;
PARAMETERS: CMP PARA_FLAG,1 ;Are there parameters?
JZ FILE_NAME ;If yes, check if filespec.
MOV DX,OFFSET FILE ;Else, point to DRAW.DAT
JMP SHORT OPEN_FILE ; and open file.
FILE_NAME: CMP FILE_FLAG,1 ;Is it a filespec?
JNZ READ_COMMAND ;If no, read the command line.
MOV DX,82H ;Else, point to filespec.
OPEN_FILE: MOV AX,3D00H ;Open file for reading.
INT 21H
JC EXIT ;If not found, exit.
MOV BX,AX ;Else, filehandle in BX.
MOV DX,OFFSET BUFFER ;Read file into buffer.
MOV CX,0F000H
MOV AH,3FH
INT 21H
MOV CX,AX ;File length in CX.
MOV SI,OFFSET BUFFER ;Initialized SI and DI
MOV DI,OFFSET BUFFER ; to head of buffer.
FORMAT: LODSB ;Get a byte.
AND AL,7FH ;Strip Wordstar high bit.
CMP AL,':' ;Is it comment character?
JZ STRIP ;If yes, strip comment.
CMP AL,'a' ;Is it lower case?
JB CK_CONTROL ;If no, check space and below.
AND AL,5FH ;Else, capitalize.
CK_CONTROL: CMP AL,32 ;Is it space or below?
JBE NEXT_FORMAT ;If yes, don't store.
STOSB ;Else store the character.
NEXT_FORMAT: LOOP FORMAT ;Get next byte.
END_FORMAT: MOV BYTE PTR [DI],13 ;Tack on carriage return as EOF.
MOV SI,OFFSET BUFFER ;Point to commands.
JMP SHORT GRAPHICS_MODE ;Change to graphics mode.
NEXT_STRIP: LODSB ;Get a byte.
AND AL,7FH ;Strip Wordstar high bit.
CMP AL,10 ;Is it linefeed?
JZ NEXT_FORMAT ;If yes get next command.
STRIP: LOOP NEXT_STRIP ;Else, skip and get next byte.
JMP SHORT END_FORMAT
;------------------------------------------------;
EXIT: INT 20H ;Terminate.
;------------------------------------------------;
;--------------------------;
; Change to graphics mode. ;
;--------------------------;
READ_COMMAND: MOV SI,82H ;Initialize pointer to commands.
GRAPHICS_MODE: CMP BYTE PTR [SI],'X' ;Low resolution command?
JNZ HIGH_RES ;If no, high resolution.
INC SI ;Else, bump pointer past "X".
PUSH SI ;Save pointer.
MOV AX,4 ;Change to 320X200 color.
INT 10H
MOV X_POSITION,159 ;Change center position.
MOV X_BOUNDRY,319 ;Change boundry.
MOV COLOR,3 ;Change default color.
MOV MAX_COLOR,3
CALL CK_NUMBER ;Get palette.
MOV BH,1
MOV AH,0BH ;Select palette.
INT 10H
POP SI ;INT 10h does not preserve SI.
JMP SHORT NEXT_COMMAND ;Get commands.
HIGH_RES: MOV AX,6 ;640X200 BW.
PUSH SI ;Preserve SI.
INT 10H
POP SI
;--------------------------------;
; This is the command processor. ;
;--------------------------------;
NEXT_COMMAND: CMP POLL_KEY,1 ;Should we poll keyboard?
JZ GET_COMMAND ;If no, skip.
MOV AH,1 ;Else, check for keystroke
INT 16H ; via BIOS.
JNZ EXIT ;If keystroke, exit.
GET_COMMAND: LODSB ;Else, get a byte.
CMP AL,13 ;Is it carriage return?
JBE EXIT ;If yes, we are done.
CMP AL,32 ;Is it space, comma or semicolon?
JZ NEXT_COMMAND ;If yes, skip.
CMP AL,','
JZ NEXT_COMMAND
CMP AL,';'
JZ NEXT_COMMAND
CK_U: CMP AL,'U' ;Is it "U" ?
JNZ CK_D ;If no, check "D".
MOV X_DIRECTION,0
MOV Y_DIRECTION,-1 ;Else, up one.
JMP DRAW_COMMAND
CK_D: CMP AL,'D' ;Is it "D" ?
JNZ CK_L ;If no, check "L".
MOV X_DIRECTION,0
MOV Y_DIRECTION,1 ;Else, down one.
JMP DRAW_COMMAND
CK_L: CMP AL,'L' ;Is it "L" ?
JNZ CK_R ;If no, check "R".
MOV X_DIRECTION,-1 ;Else left one.
MOV Y_DIRECTION,0
JMP DRAW_COMMAND
CK_R: CMP AL,'R' ;Is it "R" ?
JNZ CK_E ;If no, check "E".
MOV X_DIRECTION,1 ;Else, right one.
MOV Y_DIRECTION,0
JMP DRAW_COMMAND
CK_E: CMP AL,'E' ;Is it "E" ?
JNZ CK_F ;If no, check "F".
MOV X_DIRECTION,1 ;Else, right one.
MOV Y_DIRECTION,-1 ;Up one.
JMP SHORT DRAW_COMMAND
CK_F: CMP AL,'F' ;Is it "F" ?
JNZ CK_G ;If no, check "G".
MOV X_DIRECTION,1 ;Else, right one.
MOV Y_DIRECTION,1 ;Down one.
JMP SHORT DRAW_COMMAND
CK_G: CMP AL,'G' ;Is it "G" ?
JNZ CK_H ;If no, check "H".
MOV X_DIRECTION,-1 ;Else, left one.
MOV Y_DIRECTION,1 ;Down one.
JMP SHORT DRAW_COMMAND
CK_H: CMP AL,'H' ;Is it "H" ?
JNZ CK_B ;If no, check "B".
MOV X_DIRECTION,-1 ;Else left one.
MOV Y_DIRECTION,-1 ;Up one.
JMP SHORT DRAW_COMMAND
CK_B: CMP AL,'B' ;Is it "B" ?
JNZ CK_N ;If no, check "N".
MOV PLOT_FLAG,0 ;Else, flag no plotting.
JMP SHORT COMMAND_END
CK_N: CMP AL,'N' ;Is it "N" ?
JNZ CK_C ;If no, check "C".
MOV UPDATE_FLAG,0 ;Else, flag no update.
JMP SHORT COMMAND_END
CK_C: CMP AL,'C' ;Is it "C" ?
JNZ CK_S ;If no, check "S".
CALL CK_NUMBER ;Else, get color.
MOV COLOR,AL ;And store.
JMP SHORT COMMAND_END
CK_S: CMP AL,'S' ;Is it "S" ?
JNZ CK_M ;If no, check "M".
CALL CLS
JMP SHORT COMMAND_END
CK_M: CMP AL,'M' ;Is it "M" ?
JNZ CK_P ;If no, check "P".
CALL MOVE ;Else, move coordinates.
JMP SHORT COMMAND_END
CK_P: CMP AL,'P' ;Is it "P" ?
JNZ CK_K ;If no, check "K".
CALL PAINT ;Else, paint.
JMP SHORT COMMAND_END
CK_K: CMP AL,'K' ;Is it "K" ?
JNZ COMMAND_END ;If no, get next command.
MOV POLL_KEY,1 ;Else, flag as no key poll.
JMP SHORT COMMAND_END
DRAW_COMMAND: CALL DRAW ;Draw the dot.
CALL UPDATE_END ;Restore coordinates if needed.
COMMAND_END: JMP NEXT_COMMAND ;Get next command.
;*************;
; Subroutines ;
;*************;
;--------------------------------------------------------;
; This subroutine draws a dot if update flag is not set. ;
; Otherwise, just the coordinates are changed. ;
;--------------------------------------------------------;
DRAW: CALL CK_PLOT ;Check to see if drawing.
CALL CK_NUMBER ;Get units to move.
CMP AX,0 ;If zero, exit.
JZ END_DRAW
CALL UPDATE_START ;Check if non-update.
NEXT_DRAW: MOV CX,X_DIRECTION ;Add X direction.
ADD CX,X_POSITION
CMP CX,0 ;Check boundries.
JB END_DRAW
UPPER_X: CMP CX,X_BOUNDRY
JA END_DRAW
STORE_X: MOV X_POSITION,CX ;Store new X position.
MOV DX,Y_DIRECTION ;Add Y direction.
ADD DX,Y_POSITION
CMP DX,0 ;Check boundries.
JB END_DRAW
UPPER_Y: CMP DX,Y_BOUNDRY
JA END_DRAW
STORE_Y: MOV Y_POSITION,DX ;Store new Y position
CMP PLOT_FLAG,1 ;Is it a blank move.
JNZ LOOP_DRAW ;If yes, skip draw.
PLOT: MOV AL,COLOR ;Else, color in AL.
MOV AH,0CH ;Write dot.
INT 10H
LOOP_DRAW: DEC BX ;Draw all units?
JNZ NEXT_DRAW ;If no, draw next.
END_DRAW: RET ;Else, return.
;------------------------------------------------------------------;
; This subroutine moves the X,Y coordinates either to new absolute ;
; coordinates or relatively according to Bresenham's Algorithm. ;
;------------------------------------------------------------------;
MOVE: CALL CK_SIGN ;Is it prefaced with +/- ?
JNC DO_ABSOLUTE ;If no, absolute move.
MOV X_DIRECTION,1 ;Else, assume positive.
CMP BP,2 ;Is it positive move?
JNZ STORE_X1 ;If yes, store.
MOV X_DIRECTION,-1 ;Else, negative direction.
NEG AX ;Negate units.
STORE_X1: MOV DELTA_X,AX ;Store units.
INC SI ;Bump pointer past comma.
CALL CK_SIGN ;Do the same for the Y direction.
MOV Y_DIRECTION,1
CMP BP,2
JNZ STORE_Y1
MOV Y_DIRECTION,-1
NEG AX
STORE_Y1: MOV DELTA_Y,AX
JMP SHORT CK_SLOPE ;Plot the slope.
DO_ABSOLUTE: SUB AX,X_POSITION ;Target X - current position.
MOV X_DIRECTION,1 ;Assume positive.
JGE STORE_X2 ;Is it positive?
MOV X_DIRECTION,-1 ;If no, negative direction.
NEG AX ;Negate units.
STORE_X2: MOV DELTA_X,AX ;Store units.
INC SI ;Bump pointer past comma.
CALL CK_SIGN ;Do the same for Y direction.
SUB AX,Y_POSITION
MOV Y_DIRECTION,1
JGE STORE_Y2
MOV Y_DIRECTION,-1
NEG AX
STORE_Y2: MOV DELTA_Y,AX
CK_SLOPE: CALL CK_PLOT ;Check if drawing dots.
CALL UPDATE_START ;Check if updating position.
MOV AX,DELTA_X
CMP AX,DELTA_Y ;Is slope steep?
JL GOT_STEEP ;If yes, do steep algorithm.
CALL EASY ;Else, do easy algorithm.
JMP SHORT MOVE_END
GOT_STEEP: CALL STEEP
MOVE_END: CALL UPDATE_END ;Check if no update.
RET
;------------------------------------------------------------------;
; This is Bresenham's Algorithm for drawing a line with slope < 1. ;
;------------------------------------------------------------------;
EASY: MOV AX,DELTA_X ;Get units to plot.
MOV COUNT,AX ;Store in count.
INC COUNT ;Adjust for initial plot.
SHR AX,1 ;Divide units by two.
MOV HALF_X,AX ;Store.
MOV HALF_Y,0 ;Initialize half Y.
MOV AX,Y_DIRECTION ;Retrieve Y direction.
MOV DIRECTION,AX ;Store.
JMP SHORT EASY1 ;Already plotted first dot.
NEXT_EASY: MOV BX,1 ;One unit to draw.
CALL NEXT_DRAW ;Draw it.
EASY1: MOV Y_DIRECTION,0 ;Assume no addition.
MOV AX,DELTA_Y ;Add to delta Y to half Y.
ADD AX,HALF_Y
MOV HALF_Y,AX ;Store.
CMP AX,HALF_X ;Is > = half X?
JLE LOOP_EASY ;If no, don't change Y yet.
SUB AX,DELTA_X ;Else, update half Y
MOV HALF_Y,AX
MOV AX,DIRECTION
MOV Y_DIRECTION,AX ;Restore Y direction.
LOOP_EASY: DEC COUNT ;Done all units?
JNZ NEXT_EASY ;If no, do next.
RET
;--------------------------------------------------------------------;
; This is Bresenham's Algorithm for drawing a line with slope > = 1. ;
;--------------------------------------------------------------------;
STEEP: MOV AX,DELTA_Y ;Get units to plot.
MOV COUNT,AX
INC COUNT
SHR AX,1
MOV HALF_Y,AX ;Store.
MOV HALF_X,0 ;Initialize half X.
MOV AX,X_DIRECTION ;Retrieve X direction.
MOV DIRECTION,AX
JMP SHORT STEEP1
NEXT_STEEP: MOV BX,1
CALL NEXT_DRAW
STEEP1: MOV X_DIRECTION,0 ;Assume no addition.
MOV AX,DELTA_X ;Add delta X to half X.
ADD AX,HALF_X
MOV HALF_X,AX
CMP AX,HALF_Y ;Is it > = half Y?
JLE LOOP_STEEP ;If no, don't change X yet.
SUB AX,DELTA_Y ;Else, update half X.
MOV HALF_X,AX
MOV AX,DIRECTION
MOV X_DIRECTION,AX ;Restore X direction.
LOOP_STEEP: DEC COUNT ;Done all units?
JNZ NEXT_STEEP ;If no, do next.
RET
;------------------------------------------;
; This subroutine checks for signed moves. ;
;------------------------------------------;
CK_SIGN: XOR BP,BP ;Use BP for flag.
CMP BYTE PTR [SI],'+' ;Plus sign?
JNZ CK_MINUS ;If no, check minus sign.
INC SI ;Else bump pointer to next byte.
MOV BP,1 ;Flag as positive, relative move.
JMP SHORT GET_NUMBER ;Get the number.
CK_MINUS: CMP BYTE PTR [SI],'-' ;Is it minus?
JNZ GET_NUMBER ;If no, get number.
INC SI ;Else bump pointer to next byte.
MOV BP,2 ;Flag as negative, relative move.
GET_NUMBER: CALL CK_NUMBER ;Get the number.
CMP BP,2 ;Is it minus?
JNZ CK_ABSOLUTE ;If no check if absolute.
NEG AX ;Else, negate number.
CK_ABSOLUTE: CMP BP,0 ;Was it signed?
JNZ RELATIVE ;If yes, relative move.
CLC ;Else, flag as absolute move.
RET
RELATIVE: STC ;Flag a relative move.
RET
;----------------------------------------------------;
; This subroutine draws the first dot before moving. ;
;----------------------------------------------------;
CK_PLOT: CMP PLOT_FLAG,1 ;Is it a blank move?
JNZ END_PLOT ;If yes, skip.
MOV DX,Y_POSITION
MOV CX,X_POSITION
MOV AL,COLOR
MOV AH,0CH ;Else, draw dot.
INT 10H
END_PLOT: RET
;---------------------------------------------------------;
; These two subroutines store and, when done drawing, ;
; restore the current position if it is a no update draw. ;
;---------------------------------------------------------;
UPDATE_START: CMP UPDATE_FLAG,1 ;Are we to update postion?
JZ RET_START ;If yes, skip.
MOV AX,X_POSITION ;Else, store.
MOV X_TEMP,AX
MOV AX,Y_POSITION
MOV Y_TEMP,AX
RET_START: RET
;----------------------------
UPDATE_END: MOV PLOT_FLAG,1 ;Restore blank-move flag.
CMP UPDATE_FLAG,1 ;Were we to update position?
JZ RET_END ;If yes skip.
MOV AX,Y_TEMP ;Else, restore.
MOV Y_POSITION,AX
MOV AX,X_TEMP
MOV X_POSITION,AX
MOV UPDATE_FLAG,1 ;Reset update flag.
RET_END: RET
;---------------------------------------------------------;
; This subroutine converts decimal command number to hex. ;
;---------------------------------------------------------;
CK_NUMBER: XOR BX,BX ;Initialize to zero.
NEXT_NUMBER: CMP BYTE PTR [SI],'0' ;Is it a number?
JB END_NUMBER ;If no, we're done.
CMP BYTE PTR [SI],'9'
JA END_NUMBER
LODSB ;Get number.
SUB AL,30H ;Convert to hex.
MOV CL,AL
MOV AX,10 ;Shift decimal by ten.
XOR DX,DX
MUL BX
MOV BX,AX ;Result in BX.
XOR CH,CH
ADD BX,CX ;Add new number.
JMP SHORT NEXT_NUMBER ;Get next number.
END_NUMBER: MOV AX,BX ;Return with number in AX.
RET
;---------------------------------------------------;
; This subroutine floods the screen with a pattern. ;
;---------------------------------------------------;
CLS: PUSH DS ;Save data segment.
CALL CK_NUMBER ;Get pattern.
XOR BX,BX ;Offset zero.
MOV CX,0B800H ;Point to screen buffer.
MOV DS,CX
MOV DX,2 ;Two scan line banks.
NEXT_PATTERN: MOV CX,2000H ;One bank.
WRITE_PATTERN: MOV [BX],AL ;Store byte.
INC BX ;Bump offset.
LOOP WRITE_PATTERN ;Next byte.
ROR AL,1 ;Rotate two bytes right.
ROR AL,1
DEC DX ;Done second bank?
JNZ NEXT_PATTERN ;If no, do it now.
POP DS ;Restore data segment.
RET
;-------------------------------------------------------------------------;
; This subroutine paints the first run and then calls the recursive fill. ;
;-------------------------------------------------------------------------;
PAINT: CALL CK_NUMBER ;Get fill color.
CMP AL,MAX_COLOR ;In range?
JA END_PAINT ;If no, exit.
MOV NEW_COLOR,AL ;Else, store.
INC SI ;Bump pointer past comma.
CALL CK_NUMBER ;Get border color.
CMP AL,MAX_COLOR ;In range?
JA END_PAINT ;If no, exit.
MOV BORDER,AL ;Else, store.
MOV DX,Y_POSITION ;Get current coordinates.
MOV CX,X_POSITION
CALL READ_DOT ;Is it on screen?
JC END_PAINT ;If no, exit.
CMP AL,BORDER ;Is it border color?
JZ END_PAINT ;If yes, exit.
MOV BX,CX ;Store X.
START_LEFT: DEC CX ;Look to the left.
CALL READ_DOT ;Is it on screen?
JC END_LEFT ;If no, done.
CMP AL,BORDER ;Is it border?
JZ END_LEFT ;If yes, done.
MOV BX,CX ;Else, update X.
JMP SHORT START_LEFT ;Get next dot to left.
END_LEFT: MOV LEFT_X,BX ;Store left start of run.
PUSH BX ;Store for next call.
MOV CX,X_POSITION ;Retrieve X again.
MOV BX,CX ;Store X.
START_RIGHT: INC CX ;Look right.
CALL READ_DOT ;Is it on screen?
JC END_RIGHT ;If no, done.
CMP AL,BORDER ;Is it border?
JZ END_RIGHT ;If yes, done.
MOV BX,CX ;Else, update X.
JMP SHORT START_RIGHT ;Get next dot right.
END_RIGHT: MOV RIGHT_X,BX ;Store right end of run.
PUSH BX ;Store for next call.
SUB BX,LEFT_X ;Get length of run.
INC BX
MOV CX,LEFT_X ;Retrieve start of run.
FILL_START: MOV AL,NEW_COLOR ;Retrieve fill color.
MOV AH,0CH ;Write dot.
INT 10H
INC CX ;Next dot.
DEC BX ;Done?
JNZ FILL_START ;If no, next dot.
PUSH DX ;Store Y.
DEC DX ;Look up.
CALL FILL ;And fill shadow.
POP DX ;Restore Y.
INC DX ;Look down.
POP AX ;Retrieve end of run.
MOV RIGHT_X,AX
POP AX ;Retrieve start of run.
MOV LEFT_X,AX
CALL FILL ;Fill shadow.
END_PAINT: RET
;------------------------------------------;
; This subroutine does the recursive fill. ;
;------------------------------------------;
FILL: MOV CX,LEFT_X ;Retrieve left start.
MOV NEXT_LEFT,CX ;Store as next start.
NEXT_FILL: MOV CX,NEXT_LEFT
CALL READ_DOT ;Is it on screen?
JNC AROUND ;If no, done.
JMP END_FILL
AROUND: CMP AL,BORDER ;Is it border?
JZ CK_NEXTLEFT ;If yes, look right for start.
CMP AL,NEW_COLOR ;Is it already done?
JZ CK_NEXTLEFT ;If yes, check next left.
MOV NEXT_RIGHT,CX ;Store as next right.
MOV BX,CX
CK_LEFT: DEC CX ;Look left.
CALL READ_DOT
JC END_CK_LEFT ;Need to be filled?
CMP AL,BORDER
JZ END_CK_LEFT
MOV BX,CX ;If yes, update start and
JMP SHORT CK_LEFT ; get next left.
END_CK_LEFT: MOV NEXT_LEFT,BX ;Else, store next left.
JMP SHORT CK_RANGE
CK_NEXTLEFT: INC CX ;Look right.
CK_RIGHT_X: CMP CX,RIGHT_X ;Past end of parent run?
JG END_NEXTLEFT ;If yes, done.
CALL READ_DOT ;Does it need filling?
JC END_NEXTLEFT
CMP AL,NEW_COLOR
JZ GET_LEFT
CMP AL,BORDER
JNZ END_NEXTLEFT
GET_LEFT: INC CX ;If no, look right.
JMP SHORT CK_RIGHT_X
END_NEXTLEFT: MOV NEXT_LEFT,CX ;Else, store as new left.
MOV NEXT_RIGHT,CX ;And right.
CK_RANGE: MOV BX,NEXT_LEFT ;Is next left past right?
CMP BX,RIGHT_X ;If yes, done.
JLE FIND_RIGHT
JMP END_FILL
FIND_RIGHT: MOV BX,NEXT_RIGHT
MOV CX,BX
CK_RIGHT: INC CX ;Look right and find end of run.
CALL READ_DOT
JC END_CK_RIGHT
CMP AL,BORDER
JZ END_CK_RIGHT
GET_RIGHT: MOV BX,CX
JMP SHORT CK_RIGHT
END_CK_RIGHT: MOV NEXT_RIGHT,BX ;Store as next right.
MOV CX,NEXT_LEFT ;Get length of run.
SUB BX,CX
INC BX
FILL_RUN: MOV AL,NEW_COLOR ;And fill with new color.
MOV AH,0CH
INT 10H
INC CX
DEC BX
JNZ FILL_RUN
RECURSIVE: PUSH LEFT_X ;Store all variables on stack.
PUSH RIGHT_X
MOV CX,NEXT_LEFT
PUSH CX
MOV LEFT_X,CX
MOV CX,NEXT_RIGHT
PUSH CX
MOV RIGHT_X,CX
PUSH DX
DEC DX ;Look up.
CALL FILL ;And call on self for shadow.
POP DX ;Retrieve Y, next left
POP CX ; and next right.
MOV RIGHT_X,CX
MOV NEXT_RIGHT,CX
POP AX
MOV LEFT_X,AX
MOV NEXT_LEFT,AX
PUSH CX ;Store next right and Y
PUSH DX ; back on the stack.
INC DX ;Look down.
CALL FILL ;And call on self for shadow.
POP DX ;Retrieve all variables.
POP CX
MOV NEXT_RIGHT,CX
ADD CX,2 ;Skip to next possible next left.
MOV NEXT_LEFT,CX
POP RIGHT_X ;Restore rest of variables.
POP LEFT_X
CMP CX,RIGHT_X ;Looked all the way right?
JG END_FILL ;If yes, done.
JMP NEXT_FILL ;Else, repeat for entire shadow.
END_FILL: RET
;-----------------------------------------------------;
; This subroutine checks to see if the coordinates ;
; are on the screen. If it is, it then reads the dot. ;
;-----------------------------------------------------;
READ_DOT: CMP CX,0 ;Check column boundries.
JB OFF_SCREEN
CMP CX,X_BOUNDRY
JA OFF_SCREEN
CMP DX,0 ;Check row boundries.
JB OFF_SCREEN
CMP DX,Y_BOUNDRY
JA OFF_SCREEN
MOV AH,0DH ;Read dot.
INT 10H
CLC
RET ;Return with color in AL.
OFF_SCREEN: MOV AL,-1 ;Out of bounds.
STC
RET
BUFFER:
CODE ENDS
END START